# https://open.ziniao.com/docSupport?docId=110

"""
# 适用环境python3
"""
import hashlib
import os
import shutil
import time
import uuid
import json
import requests
import subprocess
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By


def start_ExeBrowser():
    """
    启动客户端
    :return:
    """
    try:
        cmd = [exe_path, '--run_type=web_driver', '--ipc_type=http', '--port=' + str(socket_port)]
        subprocess.Popen(cmd)
        time.sleep(5)
    except Exception:
        print('start browser process failed')
        return


def send_http(data):
    """
    通讯方式
    :param data:
    :return:
    """
    try:
        url = 'http://127.0.0.1:{}'.format(socket_port)
        response = requests.post(url, json.dumps(data).encode('utf-8'), timeout=120)
        return json.loads(response.text)
    except Exception as err:
        print(err)


def delete_all_cache():
    """
    删除所有店铺缓存
    非必要的，如果店铺特别多、硬盘空间不够了才要删除
    """
    local_appdata = os.getenv('LOCALAPPDATA')
    cache_path = os.path.join(local_appdata, 'SuperBrowser')
    if os.path.exists(cache_path):
        shutil.rmtree(cache_path)


def delete_all_cache_with_path(path):
    """
    :param path: 启动客户端参数使用--enforce-cache-path时设置的缓存路径
    删除所有店铺缓存
    非必要的，如果店铺特别多、硬盘空间不够了才要删除
    """
    cache_path = os.path.join(path, 'SuperBrowser')
    if os.path.exists(cache_path):
        shutil.rmtree(cache_path)


def open_store(store_info, isWebDriverReadOnlyMode=0, isprivacy=0, isHeadless=0, cookieTypeSave=0, jsInfo=""):
    request_id = str(uuid.uuid4())
    data = {
        "action": "startBrowser"
        , "isWaitPluginUpdate": 0
        , "isHeadless": isHeadless
        , "requestId": request_id
        , "isWebDriverReadOnlyMode": isWebDriverReadOnlyMode
        , "cookieTypeLoad": 0
        , "cookieTypeSave": cookieTypeSave
        , "runMode": "1"
        , "isLoadUserPlugin": False
        , "pluginIdType": 1
        , "privacyMode": isprivacy
    }
    data.update(user_info)

    if store_info.isdigit():
        data["browserId"] = store_info
    else:
        data["browserOauth"] = store_info

    if len(str(jsInfo)) > 2:
        data["injectJsInfo"] = json.dumps(jsInfo)

    r = send_http(data)
    if str(r.get("statusCode")) == "0":
        return r
    elif str(r.get("statusCode")) == "-10003":
        print(f"login Err {json.dumps(r)}")
        exit()
    else:
        print(f"Fail {json.dumps(r)} ")
        exit()


def close_store(browser_oauth):
    request_id = str(uuid.uuid4())
    data = {
        "action": "stopBrowser"
        , "requestId": request_id
        , "duplicate": 0
        , "browserOauth": browser_oauth
    }
    data.update(user_info)

    r = send_http(data)
    if str(r.get("statusCode")) == "0":
        return r
    elif str(r.get("statusCode")) == "-10003":
        print(f"login Err {json.dumps(r)}")
        exit()
    else:
        print(f"Fail {json.dumps(r)} ")
        exit()


def get_browser_list() -> list:
    request_id = str(uuid.uuid4())
    data = {
        "action": "getBrowserList",
        "requestId": request_id
    }
    data.update(user_info)

    r = send_http(data)
    if str(r.get("statusCode")) == "0":
        print(r)
        return r.get("browserList")
    elif str(r.get("statusCode")) == "-10003":
        print(f"login Err {json.dumps(r)}")
        exit()
    else:
        print(f"Fail {json.dumps(r)} ")
        exit()


def get_driver(open_ret_json):
    if open_ret_json.get('core_type') == 'Chromium':
        major = open_ret_json.get('core_version').split('.')[0]
        chrome_driver_path = os.path.join(driver_folder_path, 'chromedriver%s.exe') % major
        print(f"chrome_driver_path: {chrome_driver_path}")
        port = open_ret_json.get('debuggingPort')
        options = webdriver.ChromeOptions()
        options.add_argument('--log-level=3')
        options.add_experimental_option("debuggerAddress", '127.0.0.1:' + str(port))
        return webdriver.Chrome(service=Service(chrome_driver_path), options=options)
    else:
        return None


def open_baidu(driver):
    try:
        driver.get("https://www.baidu.com/")
        driver.implicitly_wait(10)
        driver.find_element(By.CLASS_NAME, 's_ipt').send_keys('紫鸟浏览器')
        time.sleep(1)
        driver.find_element(By.ID, "su").click()
        time.sleep(6)
    except Exception as e:
        print("脚本运行异常")
        print(e)
    finally:
        driver.quit()


def get_exit():
    """
    关闭客户端
    :return:
    """
    data = {"action": "exit", "requestId": str(uuid.uuid4())}

    data.update(user_info)

    print('@@ get_exit...' + json.dumps(data))
    send_http(data)


def encrypt_sha1(fpath: str) -> str:
    with open(fpath, 'rb') as f:
        return hashlib.new('sha1', f.read()).hexdigest()


def download_file(url, save_path):
    # 发送GET请求获取文件内容
    response = requests.get(url, stream=True)
    # 检查请求是否成功
    if response.status_code == 200:
        # 创建一个本地文件并写入下载的内容（如果文件已存在，将被覆盖）
        with open(save_path, 'wb') as f:
            for chunk in response.iter_content(chunk_size=1024):
                if chunk:
                    f.write(chunk)
        print(f"文件已成功下载并保存到：{save_path}")
    else:
        print(f"下载失败，响应状态码为：{response.status_code}")


def download_driver():
    response = requests.get('https://cdn-superbrowser-attachment.ziniao.com/webdriver/exe_32/config.json')
    # 检查请求是否成功
    if response.status_code == 200:
        # 获取文本内容
        txt_content = response.text
        config = json.loads(txt_content)
    else:
        print(f"下载驱动失败，状态码：{response.status_code}")
        exit()
    if not os.path.exists(driver_folder_path):
        os.makedirs(driver_folder_path)

    # 获取文件夹中所有exe文件
    driver_list = [filename for filename in os.listdir(driver_folder_path) if filename.endswith('.exe')]

    for item in config:
        item_name = item['name']
        filename = item_name + ".exe"
        local_file_path = os.path.join(driver_folder_path, filename)
        if filename in driver_list:
            # 判断sha1是否一致
            file_sha1 = encrypt_sha1(local_file_path)
            if file_sha1 == item['sha1']:
                print(f"驱动{filename}已存在，sha1校验通过...")
            else:
                print(f"驱动{filename}的sha1不一致，重新下载...")
                download_file(item['url'], local_file_path)
        else:
            print(f"驱动{filename}不存在，开始下载...")
            download_file(item['url'], local_file_path)


def use_first_browser_run_task(browser_list):
    """
    打开第一个店铺运行脚本
    :param browser_list: 店铺列表
    """
    # 如果要指定店铺ID, 获取方法:登录超览客户端->账号管理->选择对应的店铺账号->点击"查看账号"进入账号详情页->账号名称后面的ID即为店铺ID
    browser = browser_list[0]
    store_id = browser.get('browserOauth')
    store_name = browser.get("browserName")
    # 打开店铺
    print(f"=====打开店铺：{store_name}=====")
    ret_json = open_store(store_id)
    print(ret_json)
    # 使用驱动实例开启会话
    driver = get_driver(ret_json)
    # 浏览器导航到一个网页
    if driver is not None:
        print(f"=====执行脚本店铺：{store_name}=====")
        open_baidu(driver)
    print(f"=====关闭店铺：{store_name}=====")
    close_store(ret_json.get("browserOauth"))


def use_all_browser_run_task(browser_list):
    """
    循环打开所有店铺运行脚本
    :param browser_list: 店铺列表
    """
    for browser in browser_list:
        store_id = browser.get('browserOauth')
        store_name = browser.get('browserName')
        # 打开店铺
        print(f"=====打开店铺：{store_name}=====")
        ret_json = open_store(store_id)
        print(ret_json)
        # 使用驱动实例开启会话
        driver = get_driver(ret_json)
        # 浏览器导航到一个网页
        if driver is not None:
            print(f"=====执行脚本店铺：{store_name}=====")
            open_baidu(driver)
        print(f"=====关闭店铺：{store_name}=====")
        close_store(ret_json.get("browserOauth"))


if __name__ == "__main__":
    """ 需要从系统右下角角标将紫鸟浏览器退出后再运行"""

    """  
    放置chromedriver.exe的文件夹路径
    """
    driver_folder_path = r'D:\webdriver'
    exe_path = R'D:\SuperBrowser\5.265.0.28\SuperBrowser.exe'  # 客户端程序SuperBrowser.exe的路径
    socket_port = 16851  # 系统未被占用的端口

    user_info = {
        "company": "您登入紫鸟浏览器的时候输入的公司名",
        "username": "您登入紫鸟浏览器的时候输入的用户名",
        "password": "您登入紫鸟浏览器的时候输入的密码"
    }

    """  
    有店铺运行的时候，会删除失败
    删除所有店铺缓存，非必要的，如果店铺特别多、硬盘空间不够了才要删除
    delete_all_cache()

    启动客户端参数使用--enforce-cache-path时用这个方法删除，传入设置的缓存路径删除缓存
    delete_all_cache_with_path(path)
    """

    '''下载各个版本的webdriver驱动'''
    download_driver()

    print("=====启动客户端=====")
    start_ExeBrowser()

    """获取店铺列表"""
    print("=====获取店铺列表=====")
    browser_list = get_browser_list()
    if browser_list is None:
        print("browser list is empty")
        exit()

    """打开第一个店铺运行脚本"""
    use_first_browser_run_task(browser_list)

    """循环打开所有店铺运行脚本"""
    use_all_browser_run_task(browser_list)

    """关闭客户端"""
    get_exit()

